#pragma once

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;

#using <System.dll>

#include <ylLog.h>
#include <ylStringUtils.h>

#include <cliext/queue>
#include "ylLogMessage.h"
#include "ylLogMessageTemplate.h"
#include "ylLogMessageClass.h"
#include "ylLogMessageGroup.h"
#include "ylSymbolLookup.h"
#include "ylSessionData.h"
#include "ylCallstackEntry.h"
#include "ylGroupTreeView.h"
#include "ylLogDataGridView.h"


namespace yoctolog_viewer {

	/// <summary>
	/// Summary for SessionControl
	/// </summary>
	public ref class SessionControl : public System::Windows::Forms::UserControl
	{
	private: System::Windows::Forms::Panel^  infoPanel;
	private: System::Windows::Forms::Label^  connectionLabel;
	private: System::Windows::Forms::Label^  dataLabel;
	private: System::Windows::Forms::DataGridView^  callstackDataGridView;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^  FunctionColumn;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^  FileLineColumn;
	private: LogDataGridView^  logDataGridView;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^  MessageType;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^  Message;
	private: System::Windows::Forms::ToolStrip^  logDataGridViewToolstrip;
	private: System::Windows::Forms::ToolStripButton^  scrollToBottomButton;
	private: System::Windows::Forms::ToolStripButton^  copyToClipboardButton;

	public:
		SessionControl(void);
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~SessionControl();

	private: System::Windows::Forms::SplitContainer^  splitContainer1;
	private: GroupTreeView^  m_pGroupTreeView;
	private: System::Windows::Forms::TableLayoutPanel^  tableLayoutPanel1;

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			System::Windows::Forms::DataGridViewCellStyle^  dataGridViewCellStyle1 = (gcnew System::Windows::Forms::DataGridViewCellStyle());
			System::Windows::Forms::DataGridViewCellStyle^  dataGridViewCellStyle2 = (gcnew System::Windows::Forms::DataGridViewCellStyle());
			System::Windows::Forms::DataGridViewCellStyle^  dataGridViewCellStyle3 = (gcnew System::Windows::Forms::DataGridViewCellStyle());
			System::Windows::Forms::DataGridViewCellStyle^  dataGridViewCellStyle4 = (gcnew System::Windows::Forms::DataGridViewCellStyle());
			System::ComponentModel::ComponentResourceManager^  resources = (gcnew System::ComponentModel::ComponentResourceManager(SessionControl::typeid));
			this->splitContainer1 = (gcnew System::Windows::Forms::SplitContainer());
			this->m_pGroupTreeView = (gcnew GroupTreeView());
			this->tableLayoutPanel1 = (gcnew System::Windows::Forms::TableLayoutPanel());
			this->callstackDataGridView = (gcnew System::Windows::Forms::DataGridView());
			this->FunctionColumn = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->FileLineColumn = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->logDataGridView = (gcnew LogDataGridView());
			this->MessageType = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->Message = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->logDataGridViewToolstrip = (gcnew System::Windows::Forms::ToolStrip());
			this->scrollToBottomButton = (gcnew System::Windows::Forms::ToolStripButton());
			this->copyToClipboardButton = (gcnew System::Windows::Forms::ToolStripButton());
			this->infoPanel = (gcnew System::Windows::Forms::Panel());
			this->dataLabel = (gcnew System::Windows::Forms::Label());
			this->connectionLabel = (gcnew System::Windows::Forms::Label());
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->splitContainer1))->BeginInit();
			this->splitContainer1->Panel1->SuspendLayout();
			this->splitContainer1->Panel2->SuspendLayout();
			this->splitContainer1->SuspendLayout();
			this->tableLayoutPanel1->SuspendLayout();
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->callstackDataGridView))->BeginInit();
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->logDataGridView))->BeginInit();
			this->logDataGridViewToolstrip->SuspendLayout();
			this->infoPanel->SuspendLayout();
			this->SuspendLayout();
			// 
			// splitContainer1
			// 
			this->splitContainer1->Anchor = static_cast<System::Windows::Forms::AnchorStyles>((((System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Bottom) 
				| System::Windows::Forms::AnchorStyles::Left) 
				| System::Windows::Forms::AnchorStyles::Right));
			this->splitContainer1->Location = System::Drawing::Point(0, 52);
			this->splitContainer1->Name = L"splitContainer1";
			// 
			// splitContainer1.Panel1
			// 
			this->splitContainer1->Panel1->Controls->Add(this->m_pGroupTreeView);
			// 
			// splitContainer1.Panel2
			// 
			this->splitContainer1->Panel2->Controls->Add(this->tableLayoutPanel1);
			this->splitContainer1->Size = System::Drawing::Size(889, 507);
			this->splitContainer1->SplitterDistance = 294;
			this->splitContainer1->TabIndex = 2;
			// 
			// tagTreeView
			// 
			this->m_pGroupTreeView->AllowDrop = true;
			this->m_pGroupTreeView->Dock = System::Windows::Forms::DockStyle::Fill;
			this->m_pGroupTreeView->Location = System::Drawing::Point(0, 0);
			this->m_pGroupTreeView->Name = L"tagTreeView";
			this->m_pGroupTreeView->Size = System::Drawing::Size(294, 507);
			this->m_pGroupTreeView->TabIndex = 0;
			// 
			// tableLayoutPanel1
			// 
			this->tableLayoutPanel1->ColumnCount = 1;
			this->tableLayoutPanel1->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Percent, 
				100)));
			this->tableLayoutPanel1->Controls->Add(this->callstackDataGridView, 0, 2);
			this->tableLayoutPanel1->Controls->Add(this->logDataGridView, 0, 1);
			this->tableLayoutPanel1->Controls->Add(this->logDataGridViewToolstrip, 0, 0);
			this->tableLayoutPanel1->Dock = System::Windows::Forms::DockStyle::Fill;
			this->tableLayoutPanel1->Location = System::Drawing::Point(0, 0);
			this->tableLayoutPanel1->Name = L"tableLayoutPanel1";
			this->tableLayoutPanel1->RowCount = 3;
			this->tableLayoutPanel1->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Absolute, 25)));
			this->tableLayoutPanel1->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Percent, 100)));
			this->tableLayoutPanel1->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Absolute, 125)));
			this->tableLayoutPanel1->Size = System::Drawing::Size(591, 507);
			this->tableLayoutPanel1->TabIndex = 1;
			// 
			// callstackDataGridView
			// 
			this->callstackDataGridView->AllowUserToAddRows = false;
			this->callstackDataGridView->AllowUserToDeleteRows = false;
			this->callstackDataGridView->AllowUserToResizeRows = false;
			this->callstackDataGridView->ColumnHeadersHeightSizeMode = System::Windows::Forms::DataGridViewColumnHeadersHeightSizeMode::AutoSize;
			this->callstackDataGridView->Columns->AddRange(gcnew cli::array< System::Windows::Forms::DataGridViewColumn^  >(2) {this->FunctionColumn, 
				this->FileLineColumn});
			this->callstackDataGridView->Dock = System::Windows::Forms::DockStyle::Fill;
			this->callstackDataGridView->EditMode = System::Windows::Forms::DataGridViewEditMode::EditProgrammatically;
			this->callstackDataGridView->Location = System::Drawing::Point(3, 385);
			this->callstackDataGridView->Name = L"callstackDataGridView";
			this->callstackDataGridView->ReadOnly = true;
			this->callstackDataGridView->RowHeadersVisible = false;
			this->callstackDataGridView->SelectionMode = System::Windows::Forms::DataGridViewSelectionMode::FullRowSelect;
			this->callstackDataGridView->Size = System::Drawing::Size(585, 119);
			this->callstackDataGridView->TabIndex = 2;
			// 
			// FunctionColumn
			// 
			this->FunctionColumn->AutoSizeMode = System::Windows::Forms::DataGridViewAutoSizeColumnMode::Fill;
			this->FunctionColumn->HeaderText = L"Function";
			this->FunctionColumn->Name = L"FunctionColumn";
			this->FunctionColumn->ReadOnly = true;
			// 
			// FileLineColumn
			// 
			this->FileLineColumn->AutoSizeMode = System::Windows::Forms::DataGridViewAutoSizeColumnMode::Fill;
			this->FileLineColumn->HeaderText = L"File / Line";
			this->FileLineColumn->Name = L"FileLineColumn";
			this->FileLineColumn->ReadOnly = true;
			// 
			// logDataGridView
			// 
			this->logDataGridView->AllowUserToAddRows = false;
			this->logDataGridView->AllowUserToDeleteRows = false;
			this->logDataGridView->AllowUserToResizeRows = false;
			dataGridViewCellStyle1->BackColor = System::Drawing::Color::FromArgb(static_cast<System::Int32>(static_cast<System::Byte>(244)), 
				static_cast<System::Int32>(static_cast<System::Byte>(244)), static_cast<System::Int32>(static_cast<System::Byte>(244)));
			this->logDataGridView->AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1;
			this->logDataGridView->AutoSizeRowsMode = System::Windows::Forms::DataGridViewAutoSizeRowsMode::DisplayedCells;
			this->logDataGridView->BackgroundColor = System::Drawing::SystemColors::Control;
			this->logDataGridView->CellBorderStyle = System::Windows::Forms::DataGridViewCellBorderStyle::None;
			dataGridViewCellStyle2->Alignment = System::Windows::Forms::DataGridViewContentAlignment::MiddleLeft;
			dataGridViewCellStyle2->BackColor = System::Drawing::SystemColors::Control;
			dataGridViewCellStyle2->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Regular, 
				System::Drawing::GraphicsUnit::Point, static_cast<System::Byte>(0)));
			dataGridViewCellStyle2->ForeColor = System::Drawing::SystemColors::WindowText;
			dataGridViewCellStyle2->SelectionBackColor = System::Drawing::SystemColors::Highlight;
			dataGridViewCellStyle2->SelectionForeColor = System::Drawing::SystemColors::HighlightText;
			dataGridViewCellStyle2->WrapMode = System::Windows::Forms::DataGridViewTriState::True;
			this->logDataGridView->ColumnHeadersDefaultCellStyle = dataGridViewCellStyle2;
			this->logDataGridView->ColumnHeadersHeightSizeMode = System::Windows::Forms::DataGridViewColumnHeadersHeightSizeMode::AutoSize;
			this->logDataGridView->Columns->AddRange(gcnew cli::array< System::Windows::Forms::DataGridViewColumn^  >(2) {this->MessageType, 
				this->Message});
			dataGridViewCellStyle3->Alignment = System::Windows::Forms::DataGridViewContentAlignment::TopLeft;
			dataGridViewCellStyle3->BackColor = System::Drawing::SystemColors::Window;
			dataGridViewCellStyle3->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Regular, 
				System::Drawing::GraphicsUnit::Point, static_cast<System::Byte>(0)));
			dataGridViewCellStyle3->ForeColor = System::Drawing::SystemColors::ControlText;
			dataGridViewCellStyle3->SelectionBackColor = System::Drawing::SystemColors::Highlight;
			dataGridViewCellStyle3->SelectionForeColor = System::Drawing::SystemColors::HighlightText;
			dataGridViewCellStyle3->WrapMode = System::Windows::Forms::DataGridViewTriState::True;
			this->logDataGridView->DefaultCellStyle = dataGridViewCellStyle3;
			this->logDataGridView->Dock = System::Windows::Forms::DockStyle::Fill;
			this->logDataGridView->EditMode = System::Windows::Forms::DataGridViewEditMode::EditProgrammatically;
			this->logDataGridView->Location = System::Drawing::Point(3, 28);
			this->logDataGridView->MultiSelect = false;
			this->logDataGridView->Name = L"logDataGridView";
			this->logDataGridView->ReadOnly = true;
			dataGridViewCellStyle4->Alignment = System::Windows::Forms::DataGridViewContentAlignment::MiddleLeft;
			dataGridViewCellStyle4->BackColor = System::Drawing::SystemColors::Control;
			dataGridViewCellStyle4->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Regular, 
				System::Drawing::GraphicsUnit::Point, static_cast<System::Byte>(0)));
			dataGridViewCellStyle4->ForeColor = System::Drawing::SystemColors::WindowText;
			dataGridViewCellStyle4->SelectionBackColor = System::Drawing::SystemColors::Highlight;
			dataGridViewCellStyle4->SelectionForeColor = System::Drawing::SystemColors::HighlightText;
			dataGridViewCellStyle4->WrapMode = System::Windows::Forms::DataGridViewTriState::True;
			this->logDataGridView->RowHeadersDefaultCellStyle = dataGridViewCellStyle4;
			this->logDataGridView->RowHeadersVisible = false;
			this->logDataGridView->SelectionMode = System::Windows::Forms::DataGridViewSelectionMode::FullRowSelect;
			this->logDataGridView->ShowEditingIcon = false;
			this->logDataGridView->Size = System::Drawing::Size(585, 351);
			this->logDataGridView->TabIndex = 0;
			this->logDataGridView->VirtualMode = true;
			this->logDataGridView->SelectionChanged += gcnew System::EventHandler(this, &SessionControl::OnSelectionChanged);
			// 
			// MessageType
			// 
			this->MessageType->HeaderText = L"MessageType";
			this->MessageType->Name = L"MessageType";
			this->MessageType->ReadOnly = true;
			// 
			// Message
			// 
			this->Message->AutoSizeMode = System::Windows::Forms::DataGridViewAutoSizeColumnMode::Fill;
			this->Message->FillWeight = 400;
			this->Message->HeaderText = L"Message";
			this->Message->Name = L"Message";
			this->Message->ReadOnly = true;
			// 
			// logDataGridViewToolstrip
			// 
			this->logDataGridViewToolstrip->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(2) {this->scrollToBottomButton, 
				this->copyToClipboardButton});
			this->logDataGridViewToolstrip->Location = System::Drawing::Point(0, 0);
			this->logDataGridViewToolstrip->Name = L"logDataGridViewToolstrip";
			this->logDataGridViewToolstrip->Size = System::Drawing::Size(591, 25);
			this->logDataGridViewToolstrip->TabIndex = 3;
			this->logDataGridViewToolstrip->Text = L"toolStrip2";
			// 
			// scrollToBottomButton
			// 
			this->scrollToBottomButton->Checked = true;
			this->scrollToBottomButton->CheckOnClick = true;
			this->scrollToBottomButton->CheckState = System::Windows::Forms::CheckState::Checked;
			this->scrollToBottomButton->Image = (cli::safe_cast<System::Drawing::Image^  >(resources->GetObject(L"scrollToBottomButton.Image")));
			this->scrollToBottomButton->ImageTransparentColor = System::Drawing::Color::Magenta;
			this->scrollToBottomButton->Name = L"scrollToBottomButton";
			this->scrollToBottomButton->Size = System::Drawing::Size(113, 22);
			this->scrollToBottomButton->Text = L"Scroll to Bottom";
			// 
			// copyToClipboardButton
			// 
			this->copyToClipboardButton->Image = (cli::safe_cast<System::Drawing::Image^  >(resources->GetObject(L"copyToClipboardButton.Image")));
			this->copyToClipboardButton->ImageTransparentColor = System::Drawing::Color::Magenta;
			this->copyToClipboardButton->Name = L"copyToClipboardButton";
			this->copyToClipboardButton->Size = System::Drawing::Size(124, 22);
			this->copyToClipboardButton->Text = L"Copy to Clipboard";
			this->copyToClipboardButton->Click += gcnew System::EventHandler(this, &SessionControl::copyToClipboardButton_Click);
			// 
			// infoPanel
			// 
			this->infoPanel->Anchor = static_cast<System::Windows::Forms::AnchorStyles>(((System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Left) 
				| System::Windows::Forms::AnchorStyles::Right));
			this->infoPanel->BorderStyle = System::Windows::Forms::BorderStyle::FixedSingle;
			this->infoPanel->Controls->Add(this->dataLabel);
			this->infoPanel->Controls->Add(this->connectionLabel);
			this->infoPanel->Location = System::Drawing::Point(0, 3);
			this->infoPanel->Name = L"infoPanel";
			this->infoPanel->Size = System::Drawing::Size(886, 48);
			this->infoPanel->TabIndex = 7;
			// 
			// dataLabel
			// 
			this->dataLabel->Font = (gcnew System::Drawing::Font(L"Verdana", 8.25F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point, 
				static_cast<System::Byte>(0)));
			this->dataLabel->Location = System::Drawing::Point(350, -1);
			this->dataLabel->Name = L"dataLabel";
			this->dataLabel->Size = System::Drawing::Size(378, 46);
			this->dataLabel->TabIndex = 1;
			this->dataLabel->Text = L"Data received: 10 messages (1000 bytes)\r\nData processed: 9 messages (900 bytes)";
			this->dataLabel->TextAlign = System::Drawing::ContentAlignment::MiddleLeft;
			// 
			// connectionLabel
			// 
			this->connectionLabel->Font = (gcnew System::Drawing::Font(L"Verdana", 8.25F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point, 
				static_cast<System::Byte>(0)));
			this->connectionLabel->Location = System::Drawing::Point(14, -1);
			this->connectionLabel->Name = L"connectionLabel";
			this->connectionLabel->Size = System::Drawing::Size(330, 46);
			this->connectionLabel->TabIndex = 0;
			this->connectionLabel->Text = L"Client: 127.0.0.1: 1337\r\nDate: 12:15:03, 05/01/2012";
			this->connectionLabel->TextAlign = System::Drawing::ContentAlignment::MiddleLeft;
			// 
			// SessionControl
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->Controls->Add(this->infoPanel);
			this->Controls->Add(this->splitContainer1);
			this->Name = L"SessionControl";
			this->Size = System::Drawing::Size(889, 562);
			this->Load += gcnew System::EventHandler(this, &SessionControl::OnLoad);
			this->splitContainer1->Panel1->ResumeLayout(false);
			this->splitContainer1->Panel2->ResumeLayout(false);
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->splitContainer1))->EndInit();
			this->splitContainer1->ResumeLayout(false);
			this->tableLayoutPanel1->ResumeLayout(false);
			this->tableLayoutPanel1->PerformLayout();
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->callstackDataGridView))->EndInit();
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->logDataGridView))->EndInit();
			this->logDataGridViewToolstrip->ResumeLayout(false);
			this->logDataGridViewToolstrip->PerformLayout();
			this->infoPanel->ResumeLayout(false);
			this->ResumeLayout(false);

		}
#pragma endregion

	private: System::Void OnLoad(System::Object^  sender, System::EventArgs^  e);
	private: System::Void OnSelectionChanged(System::Object^  sender, System::EventArgs^  e);
	private: System::Void OnScroll(System::Object^  sender, System::Windows::Forms::ScrollEventArgs^  e);
	private: System::Void OnMouseWheel( System::Object^ sender, System::Windows::Forms::MouseEventArgs ^e );
	private: System::Void copyToClipboardButton_Click(System::Object^  sender, System::EventArgs^  e);

	public:
		void SaveSession(String ^pFilename);
		void OpenSession(String ^pFilename);
		
		System::Void ReceiveData(Object ^pClientObject);
		System::Void ProcessData(Object ^client);
		System::Void UpdateSymbols(System::Object ^pObject);

		SessionData ^GetSessionData() { return m_pSessionData; }
		void UpdateCallstackDataGrid(LogMessage ^pMessage);

		void AcceptClient(System::Net::Sockets::TcpClient ^pClient);

	private:
		unsigned int						m_hTargetProcess;
		bool								m_bShuttingDown;
		SessionData ^						m_pSessionData;
		cliext::queue< array<Byte>^ >		m_vecStreamsToProcess;
		System::Threading::Mutex			m_streamMutex;

		System::Threading::Thread ^			m_pReceiveDataThread;
		System::Threading::Thread ^			m_pProcessDataThread;

		System::Threading::Thread ^			m_pUpdateSymbolsThread;
		System::Collections::Generic::List<unsigned int>	m_vecSymbolsToResolve;
		System::Threading::Mutex			m_xSymbolsMutex;

		array<Byte>^						m_pBuffer;

		delegate void UpdateMessageLogViewDelegate();
		delegate void NetMsgDelegate(Int64 pMsg);
		delegate void UpdateInfoBarDelegate();

		UpdateMessageLogViewDelegate ^pUpdateMessageLogViewDelegate;
		NetMsgDelegate ^pCreateLogItemDelegate;
		UpdateInfoBarDelegate ^pUpdateInfoBar;

		void UpdateInfoBar();
		void CreateLogItemMethod(Int64 pMsg);
		void UpdateMessageLogView();
		void OnGroupSelected(LogMessageGroup ^pGroup);
		void SetSessionData(SessionData ^pSessionData);

};
}
